using System;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Content;
using System.Collections.Generic;
using WinForms = System.Windows.Forms;

namespace Najak
{
	//public struct GameTime
	//{
	//   public TimeSpan TotalGameTime;
	//   public TimeSpan ElapsedGameTime;

	//   public GameTime(TimeSpan totalTime, TimeSpan frameDelta)
	//   {
	//      TotalGameTime = totalTime;
	//      ElapsedGameTime = frameDelta;
	//   }
	//}

	public abstract partial class App
	{
		static public App Instance;

		static public Func<IAppHost, object, App> Create;

		static public bool IsEditorMode = false;

		static public bool IsPaused = false;

		static public bool IsKeyboardDisabled = false;

		public bool PauseRendering;

		public GameTime GameTime;
		public TimeSpan Time;
		public float TimeDelta;
		public double Seconds;

		protected string DebugMessage;
		protected TimeSpan _debugMessageExpiration;

		// Resources for drawing.
		//private GraphicsDeviceManager _graphics;
		public SpriteBatch SpriteBatch;
		public Drawing.Shapes Shapes;

		// Global content.
		static public SpriteFont _hudFont;
		static public SpriteFont _bigFont;

		public Portal.PortalTarget CurrentCheckPoint;

		public Scene Scene { get { return Scene.Manager.Instance.CurrentScene; } }

		private const int TargetFrameRate = 60;

		public int MaxScene;

		public ContentManager Content;
		public IAppHost AppHost;

		public Point ScreenSize
		{
			get { return AppHost.ScreenSize; }
		}
		public Point ScreenLocation
		{
			get { return AppHost.ScreenLocation; }
		}

		public App(IAppHost drawer, object contentMgr)
		{
			AppHost = drawer;

			Instance = this;
			//_graphics = new GraphicsDeviceManager(this);
			//_graphics.PreferredBackBufferWidth = BackBufferWidth;
			//_graphics.PreferredBackBufferHeight = BackBufferHeight;

			Content = contentMgr as ContentManager;

			if (Content == null)
			{
				Content = new ContentManager(AppHost.Services, "Content");
				Content.RootDirectory = "Content";
			}

			// Framerate differs between platforms.
			//TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / TargetFrameRate);

			//IsMouseVisible = true;
			//IsFixedTimeStep = true;
			//TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 16);
			InputHandler.Instance.RegisterForKeyEvent(this, Keys.G, ToggleEditor, false, true);
			InputHandler.Instance.RegisterForKeyEvent(this, Keys.S, SaveGameState, false, true);
			InputHandler.Instance.RegisterForKeyEvent(this, Keys.L, LoadGameState, false, true);

			Portal.PortalTarget pd = new Portal.PortalTarget("EditorScene,0,W");
		}

		private void SaveGameState(Keys key)
		{
			if (!IsEditorMode)
			{
				Scene.CaptureDynamicContent(Scene);
				State s = new State(this);
				s.Save();
				SetDebugMessage("GameStateSaved", 3);


			}
		}
		private void LoadGameState(Keys key)
		{
			if (!IsEditorMode)
			{
				State s = State.Load();
				s.Apply(this);
				SetDebugMessage("GameStateLoaded", 3);
			}
		}

		private void ToggleEditor(Keys key)
		{
			if (IsEditorMode)
			{

				if (Scene.Instance != null)
				{
					Scene.Instance.SaveIfNeeded();
					Scene.Instance.DoNotSaveOnLeaving = true;
				}

				IsEditorMode = false;
				Scene.DynamicContentRegistry.Clear();
				Scene.Instance.Dispose();
				ReloadCurrentScene(false);
			}
			else
			{
				IsEditorMode = true;
				Scene.DynamicContentRegistry.Clear();
				ReloadCurrentScene(false);
				//Controls.EditorWindow.ShowEditor();
			}
		}

		public void LoadContent()
		{
			SpriteBatch = new SpriteBatch(AppHost.GraphicsDevice);
			Shapes = new Drawing.Shapes();

			_hudFont = Content.Load<SpriteFont>("Fonts/Hud");
			_bigFont = Content.Load<SpriteFont>("Fonts/Hud");

			CurrentCheckPoint = new Portal.PortalTarget("0,0,W");

			string[] files = System.IO.Directory.GetFiles(Scene.Manager.SceneFolder);
			MaxScene = files.Length - 1;

			LoadNextScene(CurrentCheckPoint, true);

		}

		static public string LastCommand;


		public void Update(GameTime gameTime)
		{
			GameTime = gameTime;
			TimeDelta = (float)gameTime.ElapsedGameTime.TotalSeconds;
			Seconds = gameTime.TotalGameTime.TotalSeconds;
			Time = TimeSpan.FromSeconds(Seconds);

			HandleInput();
			InputHandler.Instance.CheckForEvents();
			if (!IsPaused)
			{
				if (IsEditorMode)
				{
					UpdateEditorMode(gameTime);
				}
				else
				{
					Scene.Update(gameTime);
				}
			}
		}


		private void UpdateEditorMode(GameTime gameTime)
		{
			Editor.GameEditorPlayer.Instance.Update(gameTime);
		}

		private void HandleInput()
		{
			if (Scene.ReachedPortal != null)
			{
				LoadNextScene(Scene.ReachedPortal, true);
				return;
			}
		}

		public void LoadNextScene(Portal.PortalTarget pd, bool saveCurrentScene)
		{

			if (Scene != null)
			{
				Scene.CaptureDynamicContent(Scene);

				if (IsEditorMode || !saveCurrentScene)
				{
					Scene.DynamicContentRegistry.Clear();
				}
				Scene.Dispose();
			}

			Scene.Manager.Instance.LoadSceneByName(pd.SceneName, pd);
		}




		public void ReloadCurrentScene(bool saveCurrentScene)
		{
			LoadNextScene(Scene.SendingPortal, saveCurrentScene);
		}


		public void Draw()
		{
			AppHost.GraphicsDevice.Clear(Color.LightGray);
			SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);

			Scene.Draw(SpriteBatch);

			if (PostDrawCommands != null)
				PostDrawCommands();
			PostDrawCommands = null;

			if (IsEditorMode)
				DrawEditorHud();
			else
				DrawHud();
			SpriteBatch.End();
		}

		public event System.Action PostDrawCommands;

		static protected float _timeTilStatusMessageExpires;
		static protected string _statusMessage;

		static public void ShowMessage(int seconds, string text)
		{
			_statusMessage = text;
			_timeTilStatusMessageExpires = 1000 * seconds;
		}

		private void DrawEditorHud()
		{
			Rectangle titleSafeArea = AppHost.GraphicsDevice.Viewport.TitleSafeArea;
			Vector2 hudLocation = new Vector2(titleSafeArea.X, titleSafeArea.Y);
			Vector2 center = new Vector2(titleSafeArea.X + titleSafeArea.Width / 2.0f, titleSafeArea.Y + titleSafeArea.Height / 2.0f);
			hudLocation.Y = 600;
			DrawShadowedString(_hudFont, "Scene: " + (this.Scene.Name), hudLocation, Color.Brown);

			if (!String.IsNullOrEmpty(DebugMessage))
			{
				if (Time < _debugMessageExpiration)
				{
					hudLocation.Y += 40;
					DrawShadowedString(_hudFont, DebugMessage, hudLocation, Color.Yellow);
				}
				else
				{
					DebugMessage = null;
				}
			}

			hudLocation.Y += 40;

			if (_timeTilStatusMessageExpires > 0)
			{
				DrawShadowedString(_hudFont, _statusMessage, hudLocation, Color.Yellow);
				_timeTilStatusMessageExpires -= (float)GameTime.ElapsedGameTime.TotalMilliseconds;
			}

		}

		abstract public void DrawHud();

		public void DrawShadowedString(SpriteFont font, string value, Vector2 loc, Color color)
		{
			SpriteBatch.DrawString(font, value, loc + new Vector2(1.0f, 1.0f), Color.Black);
			SpriteBatch.DrawString(font, value, loc, color);
		}
		public void SetDebugMessage(string msg, int duration)
		{
			DebugMessage = msg;
			_debugMessageExpiration = Time + TimeSpan.FromSeconds(duration);
		}
	}
}
